package model.game;

import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Iterator;

import view.DebugPanel;

import model.enemy.AbstractEnemy;
import model.enemy.YellowEnemy;
import model.player.Player;

/**
 * This class is responsible for enemy waves.
 * It builds a collection of AbstractEnemy and place each enemy on the path. 
 * It also moves enemy once the game is started
 * 
 * @author alexandre.altun
 */
public class EnemyWave {
	
	private static final long serialVersionUID = 1L;

	private EnemiesThread _enemiesThread;
	
	private ArrayList<AbstractEnemy> _enemies;
	
	private Path _path;
	
	private Player _player;
	
	private boolean _buildingWave = false;
	
	private int _currentWave;
	
	private boolean _running = false;
	
	
	/**
	 * Class constructor. 
	 * It takes a Path object as parameter which contains the path
	 * on which enemies will move. 
	 * 
	 * @param path
	 * @param player
	 */
	public EnemyWave(int waveNumber, Path path, Player player) {
		
		_path = path;
		_player = player;
		_currentWave = waveNumber;
		_buildWave();
	}
	
	
	public ArrayList<AbstractEnemy> getEnemies() {
		
		return _enemies;
	}
	
	
	/**
	 * Build enemies of this wave
	 */
	private void _buildWave() {
		
		switch (_currentWave) {
			case 1: _enemies = yellowWave(); break;
			case 2: _enemies = yellowWave(); break;
		}
		
		if (null == _enemies) return; 
			
		_running = true;
	}
	
	
	/**
	 * Build a wave of yellow enemies
	 */
	public ArrayList<AbstractEnemy> yellowWave() {
		
		ArrayList<AbstractEnemy> wave = new ArrayList<AbstractEnemy>(); 
		for (int i = 0; i < 10; i++) {
			Point startPos = _path.getStartPos(15 + 20*wave.size());
			wave.add(new YellowEnemy(_path, _player, startPos, this));
		}
		return wave;
		
	}
	
	
	public ArrayList<AbstractEnemy> testFixedWave() {
		
		ArrayList<AbstractEnemy> wave = new ArrayList<AbstractEnemy>();
		wave.add(new YellowEnemy(_path, _player, new Point(112, 137), this));
		return wave;
	}
	
	
	/**
	 * Increment the current wave number and build the next one
	 */
	public synchronized boolean buildNextWave() {
		
		if (!hasNextWave()) return false;
		
		stop();
		
		_buildingWave = true;
		_currentWave++;
		_buildWave();
		_buildingWave = false;
		
		start();
		
		return true;
	}
	
	
	/**
	 * Is there a next wave
	 */
	public boolean hasNextWave() {
		
		return (_currentWave < 2);
	}
	
	
	/**
	 * Has the wave been cleared?
	 */
	public boolean waveCleared() {
		
		return (!_buildingWave && !_running);
	}
	
	
	/**
	 * Launch the thread which moves enemies
	 */
	public void start() {
		
		_enemiesThread = new EnemiesThread();
		_enemiesThread.start();
	}
	
	
	public void stop() {
		
		_enemiesThread.interrupt();
		_enemiesThread = null;
	}
	
	
	/**
	 * Draw all enemies on bufferGame
	 * 
	 * @param bufferGame
	 */
	public void drawEnemies(Graphics bufferGame) {
		for (Iterator<AbstractEnemy> it = _enemies.iterator(); it.hasNext();) {
			AbstractEnemy enemy = it.next();
			enemy.draw(bufferGame);
		}
	}
	
	
	/**
	 * Notify all enemies that they have to move
	 */
	private boolean moveEnemies() {
		
		if (_enemies.size() == 0) return false;
		
		for (Iterator<AbstractEnemy> it = _enemies.iterator(); it.hasNext();) {
			AbstractEnemy enemy = it.next();
			enemy.move();
		}
		
		return true;
	}
	
	
	public void enemyIsDead(AbstractEnemy enemy) {
		
		_enemies.remove(enemy);
	}
	
	
	/**
	 * Thread responsible for moving enemies on the path each 10ms
	 * 
	 * @author alexandre.altun
	 */
	class EnemiesThread extends Thread {

		public void run() {
			while(_running) {
				try {
					
					if (false == moveEnemies()) {
						_running = false;
					}
					
					DebugPanel.getInstance().incFps();
					sleep( 10 );
				} catch ( Exception e ) {} 
			}
		}
	}   
	
}
